<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>循环检测</title>
</head>
<body>
    <div id="test1" style="background: red;width: 80%;height: 400px;">
        <div id="test2" style="background: blue;padding: 20px;display: inline-block;">
            <div id="test3" style="background: green;width: 100px;height: 100px">
        
            </div>
        </div>
    </div>
    <script>
        class DomResizeWatcher{
            constructor(){
                this.datas = new Map()

                this._init()
            }

            _init(){
                this._check()
            }

            _check(){
                Array.from(this.datas.values()).forEach(data => {
                    data.check()
                })

                requestAnimationFrame(this._check.bind(this))
            }

            addResizeEventListener(dom, fun){
                let data = this.datas.get(dom)
                if(!data){
                    data = new DomResizeWatcherData(dom)
                    this.datas.set(dom, data)
                }
                data.addResizeEventListener(fun)
            }

            removeResizeEventListener(dom, fun){
                let data = this.datas.get(dom)
                if(!data) return

                data.removeResizeEventListener(fun)

                if(data.getFunCount() > 0) return

                this.datas.delete(dom)
            }
        }

        class DomResizeWatcherData{
            constructor(dom){
                this.dom = dom
                this.funs = new Set()
                this.size = this._getDomSize()
            }

            _getDomSize(){
                let height = this.dom.clientHeight
                let width = this.dom.clientWidth

                return {
                    height,
                    width
                }
            }

            _trigger(){
                let dom = this.dom
                this.funs.forEach(fun => {
                    fun.apply(dom)
                })
            }

            getFunCount(){
                return this.funs.size
            }

            addResizeEventListener(fun){
                this.funs.add(fun)
            }

            removeResizeEventListener(fun){
                this.funs.delete(fun)
            }

            check(){
                let size = this._getDomSize()
                if(size.height !== this.size.height 
                    || size.width !== this.size.width){
                    this._trigger()
                    this.size = size
                }
            }
        }

        let watcher = new DomResizeWatcher()
        watcher.addResizeEventListener(document.getElementById("test1"), _ => {
            console.log("test1 resize!")
        })
        watcher.addResizeEventListener(document.getElementById("test2"), _ => {
            console.log("test2 resize!")
        })
        watcher.addResizeEventListener(document.getElementById("test3"), _ => {
            console.log("test3 resize!")
        })
        
        //循环创建
        // for(let i = 0; i < 5000; i++){
        //     let div = document.createElement("div")
        //     div.style="background: red;width: 80%;height: 20px;"
        //     div.innerHTML = i
        //     document.body.appendChild(div)
        //     watcher.addResizeEventListener(div, _ => {
        //         //do someting
        //     })
        // }

    </script>
</body>
</html>